关于 this
this
关键字是 JavaScript 中最复杂的机制之一,它是一个很特别的关键字,被自动定义在所有函数的作用域中。
this
提供了一种更优雅的方式来隐式『传递』一个对象的引用,因此可以将 API 设计得更加简洁并且易于复用。
注意:
1.this
不指向自身
1 | function foo(num) { |
以上代码显然没有按照我们预期的效果运行,问题就出在 this
并不指向自身上,以下是修改的方案:
1 | function foo(num) { |
使用 call
方法强制绑定 this
指向 foo
,解决了之前的问题。
2.this
不代表它的作用域
在某种情况下,this
指向函数的作用域,但有时又不是。
this
在任何情况下都不指向函数的词法作用域。在 JavaScript 内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域『对象』无法通过 JavaScript 代码访问,它存在于 JavaScript 引擎内部。
3.this
到底是什么
this
是在运行时进行绑定的,并不是在编写时,它的上下文取决于函数调用时的各种条件。所以,this
的绑定和声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this
就是记录的其中一个属性,会在函数执行的过程中用到。
调用位置
只有清晰地了解了调用位置,才能明白 this
到底引用的是什么。
调用位置是函数在代码中被调用的位置(而不是声明的位置)。最重要的是要分析调用栈(就是为了到达当前执行位置所调用的所有函数)。我们关心的调用位置就在当前正在执行的函数的前一个调用中。
下面通过代码展示什么是调用栈和调用位置:
1 | function baz() { |
绑定规则
1.默认绑定
2.隐式绑定
对象属性引用链中只有最顶层或者说最后一层会影响调用位置
1 | function foo() { |
1 | function foo() { |
隐式丢失
1 | function foo() { |
3.显式绑定
可以使用函数的 call(..)
和 apply(..)
方法。
4.new
绑定
包括内置对象函数在内的所有函数都可以用 new
来调用,这种函数调用被称为构造函数调用。
使用 new
来调用函数,会自动执行下面的操作。
- 创建(或者说构造)一个全新的对象。
- 这个新对象会被执行『原型』连接。
- 这个新对象会绑定到函数调用的
this
。 - 如果函数没有返回其他对象,那么
new
表达式中的函数调用会自动返回这个新对象